Classificação

Um classificador é um modelo computacional capaz de predizer classes para determinado conjunto de informações, a partir de um conhecimento prévio de o que caracteriza cada classe. Por exemplo, se você possui diversas categorias de projetos de leis (educacional, saúde, segurança, etc...), é possível criar um classificador que, a partir do texto de um projeto, consegue identificar a categoria a que ele pertence.

Para ser capaz de fazer uma classificação bem sucedida, o classificador precisa antes passar por um processo de aprendizado (ou treinamento). Esse processo consiste em apresentar ao modelo computacional exemplos de dados dos quais já se sabe a classe, de forma que o classificador consiga identificar em suas características (ou atributos) os critérios que definem cada classe.

Assim como para a clusterização, existem disversas técnicas disponíveis para essa tarefa. Para este exercício, usaremos o SVM (Support Vector Machine) como classificador - você pode ler mais a respeito em [0]. Outros modelos, como as Redes Neurais Artificiais também estão disponíveis através da biblioteca scikit-learn. Encorajamos o estudo destes outros modelos, mas prezando a simplicidade não os incluiremos neste tutorial.

Exemplo: Base Iris

Neste exemplo, aprenderemos a utilizar um classificador para encontrar a classe correta de uma flor.

Para isso, escolhemos o banco de dados Iris [1], que contem informações sobre 3 subespécies diferentes da flor Iris.

Este banco tem 150 exemplos, 50 de cada classe:

  • Setosa
  • Versicolour
  • Virginica

Cada exemplo possui 4 atributos numéricos:

  • Comprimento da sépala (em centímetros);
  • Largura da sépala (em centímetros);
  • Comprimento da pétala (em centímetros);
  • Largura da pétala (em centímetros);

Nossa tarefa é: Dada a descrição de uma flor (os 4 números), descobrir qual é sua subespécie. Usaremos o algoritmo SVM - Support Vector Machine da biblioteca scikit-learn para essa tarefa.


In [ ]:
import numpy as np
import pylab as pl
from sklearn import datasets, svm

A primeira coisa que devemos fazer é carregar as informações sobre as flores. Armazenaremos elas em duas variáveis: X e Y.

A variável X é uma matriz, em cada linha temos uma flor diferente (total = 150 linhas) e em cada coluna uma característica daquela flor (total = 4 colunas).
Enquanto isso, guardaremos na variável y a classe correta daquela flor para utilizarmos durante o treinamento e, depois, medirmos a acurácia da nossa classificação (total = 150 linhas).


In [ ]:
iris = datasets.load_iris() #carrega a base iris
X = iris.data
y = iris.target  #guarda o "gabarito", com informações das classes
print 'Linhas de X: ' + str(len(X)) + ', Colunas de X: ' + str(len(X[0]))
print 'Linhas de Y: ' + str(len(y))

Separação dos dados em treinamento e teste

Agora que temos todas as flores, suas descrições e classificação correta, queremos separá-las em dois conjuntos distintos:

  • Treinamento;
  • Teste.

O conjunto de treinamento serve para treinar o nosso classificador. Entregaremos para o SVM as flores do conjunto de treinamento, com sua descrição (4 números) e sua classe (1 das 3 classes possíveis - número de 0 a 2). A partir daí, o SVM tentará aprender como identificar cada espécie de flor com base na sua descrição.

Definimos que 50% das flores serão usadas no conjunto de treinamento, e as 50% restantes no conjunto de testes.
O conjunto de testes não é usado durante o treinamento. Assim, garantimos que o classificador nunca os viu antes, e teremos uma medição confiável de quão bom ele é - já que estamos classificando flores "desconhecidas" até o momento.


In [ ]:
n_flores = len(X)
porcentagem_treino = 0.5 # No intervalo 0..1; 0.8 = 80%

np.random.seed(0)
ordem = np.random.permutation(n_flores)
X = X[ordem]
y = y[ordem].astype(np.float)

X_treino = X[:int(porcentagem_treino * n_flores)]
y_treino = y[:int(porcentagem_treino * n_flores)]
X_teste = X[int(porcentagem_treino * n_flores):]
y_teste = y[int(porcentagem_treino * n_flores):]

print 'Tamanho do conjunto de treinamento: ' + str(len(y_treino))
print 'Tamanho do conjunto de testes: ' + str(len(y_teste))

Treinamento do classificador

Com os conjuntos de treino e testes separados, podemos treinar o nosso classificador (SVM).
Inicialmente, definimos quais parâmetros vamos usar.

O SVM tem vários tipos de kernel (funções usadas no momento de definir um hiperplano para classificação), como RBF, Linear, Polinomial etc. Para este exemplo, usaremos o kernel linear - que é o mais simples e rápido. Para mais informações sobre kernels e parâmetros, visite [2].

O comando fit, então, realiza o treinamento.


In [ ]:
classificador = svm.SVC(kernel='linear')
classificador.fit(X_treino, y_treino);

Com o classificador treinado, podemos tentar predizer as classes de flor para o nosso conjunto de testes, sem olhar a variável y_teste, que contém as classes verdadeiras.


In [ ]:
y_classificado = classificador.predict(X_teste)
print y_classificado

Testando o classificador

Agora que temos os valores que nosso classificador atribuiu para cada flor, podemos conferir na variável y_teste, que armazena os valores corretos, qual foi a acurácia de nosso classificador.


In [ ]:
print y_classificado
print y_teste

acertos = sum(y_teste == y_classificado)

print str(acertos) + ' acertos de ' + str(len(y_teste)) + ' testes. Acurácia = %.2f%%' % (acertos / float(len(y_teste)) * 100)

Usando 50% das nossas flores no treinamento, conseguimos acurácia de 98.67% no conjunto de teste - 1 erro em 75.
Essa é uma taxa alta, que pode ser melhorada. Quanto mais exemplos forem usados no conjunto de treino, melhor o modelo poderá ficar; em contrapartida, quanto maior o conjunto de treino, menor o conjunto de teste - e menos confiança temos no resultado. Então, precisamos encontrar um ponto em que aceitamos os resultados obtidos como confiáveis, e não existe regra para isso.

Em bancos maiores e mais complexos, é comum usar mais dados para o conjunto de treino (80%, por exemplo).

Tarefa

  • Mude a porcentagem de flores que será utilizada durante o treinamento. Teste com: 10%, 20%, 30%, 40%, 70% e 80%. Como isso afeta o resultado do classificador? Você consegue explicar o motivo das diferenças?
  • Treine um classificador para a base de dígitos. Utilize "datasets.load_digits". Note que desta vez, a base tem 10 classes e 64 atributos numéricos. Lembre-se de testar diferentes porcentagens para o conjunto de treinamento.

In [ ]:
# seu código aqui!

In [ ]:


In [ ]:

Referências